package com.noble.glamour.module.logic.socket;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.text.TextUtils;

import com.noble.glamour.module.logic.application.App;
import com.noble.glamour.module.logic.application.ModuleMgr;
import com.noble.glamour.module.logic.config.UrlParam;
import com.noble.glamour.module.logic.socket.listener.IMListener;
import com.noble.glamour.module.logic.socket.listener.SendCallBack;
import com.noble.glamour.module.logic.socket.stream.NetStream;
import com.noble.glamour.module.logic.socket.utils.ConnectStatus;
import com.noble.glamour.module.logic.socket.utils.IMUtils;
import com.noble.glamour.module.logic.socket.utils.SocketState;
import com.noble.library.host.Hosts;
import com.noble.library.log.PToast;
import com.noble.library.observe.MsgMgr;
import com.noble.library.observe.MsgType;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 对外开放接口：
 * <p>
 * 即时通许代理，负责将接收到的服务器消息通知给上层
 */
public class IMProxy {
    private static class SingletonHolder {
        static IMProxy instance = new IMProxy();
    }

    public static IMProxy getInstance() {
        return SingletonHolder.instance;
    }

    private Set<IMListener> noTypeMapListener = new LinkedHashSet<>();  // 维护注册各个消息监听接口
    private Intent sIntent = null;

    /**
     * 注册一个监听者，将监听者和所有消息类型绑定
     *
     * @param imListener 监听者实例
     */
    public void attach(final IMListener imListener) {
        noTypeMapListener.add(imListener);
    }

    /**
     * 取消注册的监听者，解除监听者的所有绑定
     *
     * @param imListener 监听者实例
     */
    public void detach(final IMListener imListener) {
        noTypeMapListener.remove(imListener);
    }

    // ==================================== 开始建立连接 ====================================

    /**
     * 代理和服务器建立连接
     */
    public void connect() {
        if (status != ConnectStatus.NO_CONNECT && status != ConnectStatus.DISCONNECTED && iCoreService != null) {
            login();
            return;
        }

        // 服务绑定
        Context context = App.context;
        sIntent = new Intent();
        sIntent.setClass(context, CoreService.class);
        try {
            context.startService(sIntent);//启动CoreService服务
            if (context.bindService(sIntent, connection, Context.BIND_AUTO_CREATE)) {//服务是否绑定成功
                if (status == ConnectStatus.NO_CONNECT) {//如果本地记录的连接状态是未连接，就更新为已绑定，否则更新为重连
                    status = ConnectStatus.BINDING;
                } else {
                    status = ConnectStatus.REBINDING;
                }
            }
        } catch (SecurityException e) {
            IMUtils.logThrowable(e);
        }
    }

    /**
     * 使用存储的账户密码进行登录
     */
    private void login() {
        long uid = ModuleMgr.getLoginMgr().getUid();
        String auth = ModuleMgr.getLoginMgr().getAuth();
        if (uid == 0 || TextUtils.isEmpty(auth)) {
            IMUtils.log("---IMProxy--->login：auth is empty.");
            return;
        }

        try {
            if (iCoreService != null) iCoreService.login();
        } catch (Exception e) {
            IMUtils.logThrowable(e);
        }
    }

    /**
     * 退出登录，即断开即时通讯的连接，同时清除登录用的token
     */
    public void logout() {
        try {
            if (iCoreService != null) iCoreService.logout();
        } catch (Exception e) {
            IMUtils.logThrowable(e);
        }
    }

    /**
     * 代理和服务器断开连接（默认不主动断开连接，特殊情况调用）
     */
    public void disconnect() {
        if (status != ConnectStatus.CONNECTED) {
            return;
        }

        if (sIntent != null) {//解绑并停止服务
            App.context.unbindService(connection);
            App.context.stopService(sIntent);
        }
    }

    // =======================================  消息发送 ===============================================

    /**
     * socket发消息:  外层调用该方法，保证再CoreService进程中执行
     */
    public void send(NetData netData) {
        try {
            // coreService线程池发送
            if (iCoreService != null) iCoreService.sendMsg(netData);
        } catch (Exception e) {
            IMUtils.logThrowable(e);
        }
    }

    /**
     * Http发消息
     *
     * @param netData  数据包封装
     * @param callBack 发送消息回调
     */
    public void send(NetData netData, SendCallBack callBack) {
        sendByHttp(netData, callBack);
    }

    private void sendByHttp(final NetData sendData, final SendCallBack callBack) {
        HashMap<String, Object> getParam = new HashMap<>();
        getParam.put("uid_from", sendData.getFromId());
        getParam.put("uid_to", sendData.getTuid());
        getParam.put("type_msg", sendData.getMsgType());

        String urlpush = ModuleMgr.getCommonMgr().getSetting().getUrlPush();
        if (TextUtils.isEmpty(urlpush)) {
            urlpush = Hosts.FATE_IT_MSG;
        }
        ModuleMgr.getHttpMgr().reqJsonAndGetHttp(UrlParam.sendMessage.resetHost(urlpush), getParam, sendData.getContent(), response -> {
            if (response.isOk()) {
                if (callBack != null) {
                    callBack.onResult(sendData.getMessageId(), sendData.getFromId(), sendData.getContent());
                }
                JSONObject jsonObject = response.getResponseObject();
                int online = jsonObject.optInt("Online");
                handleOnline(online);
            } else {
                if (callBack != null) {
                    callBack.onSendFailed(sendData);
                }
            }
        });
    }

    // 处理在线状态
    private void handleOnline(int online) {
        if (online == 1) {  // 双方都在线， 不做处理
            return;
        }

        if (online == -1) {  // 本人不在线，重新发送登录注册
            AutoConnectMgr.getInstance().reLogin();
            return;
        }

        if (online == -2) {    // 对方不在线
            PToast.showShort("对方已离线");
            return;
        }

        if (online == -3) {   // 双方不在线
            PToast.showShort("对方已离线");
            AutoConnectMgr.getInstance().reLogin();
        }
    }

    // ================================ CoreService connection ======================================

    private ChatServiceConnection connection = new ChatServiceConnection();

    private class ChatServiceConnection implements ServiceConnection {

        @Override
        public void onServiceDisconnected(final ComponentName name) {
            status = ConnectStatus.DISCONNECTED;
            iCoreService = null;
            connect();
        }

        @Override
        public void onServiceConnected(final ComponentName name, final IBinder service) {
            if (status == ConnectStatus.BINDING || status == ConnectStatus.REBINDING) {
                iCoreService = ICoreService.Stub.asInterface(service);
                setCSCallback();

                //发送CoreService启动消息
                login();
            }
            status = ConnectStatus.CONNECTED;
        }
    }

    private static ConnectStatus status = ConnectStatus.NO_CONNECT;//默认连接状态为未连接

    /**
     * 调用{@link CoreService}的接口实例
     */
    private ICoreService iCoreService = null;

    /**
     * 将{@link CoreService}
     * 对{@link IMProxy}的回调在这里设置
     */
    private void setCSCallback() {
        try {
            if (iCoreService != null) iCoreService.setCallback(iCSCallback);
        } catch (Exception e) {
            IMUtils.logThrowable(e);
        }
    }

    /**
     * 将{@link CoreService}
     * 对{@link IMProxy}的回调清除
     */
    private void removeCSCallback() {
        try {
            if (iCoreService != null) iCoreService.setCallback(null);
        } catch (Exception e) {
            IMUtils.logThrowable(e);
        }
    }

    // ================================ ICSCallback.aidl start======================================
    /**
     * {@link CoreService}回调IMProxy的接口实例
     */
    private ICSCallback iCSCallback = new CSCallback();

    private class CSCallback extends ICSCallback.Stub {
        @Override
        public void onMessage(final NetData data) {
            final long msgId = data.getMessageId();
            //消息接收反馈
            if (App.uid > 0 && msgId != -1) {
                send(NetStream.getLoopbackData(msgId));
            }
            IMProxy.this.onMessage(data);
        }

        @Override
        public void onSendMsgError(final NetData data) {
        }

        @Override
        public void onStatusChange(int type, String msg) {
            IMProxy.this.onStatusChange(type, msg);
        }

        @Override
        public void accountInvalid(int reason, String content) {
            IMUtils.accountInvalid(reason, content);
        }

        @Override
        public void heartbeatStatus(boolean isBeating) {
            IMProxy.this.setSocketValidStatus(isBeating);
        }

        @Override
        public void changeDomainName() {
            // 域名检测，做域名灾备处理
        }
    }

    /**
     * 处理{@link CoreService} 回调过来的消息<br>
     * <p>
     * 将消息分发给各个监听者
     */
    public void onMessage(NetData data) {
        for (IMListener imListener : noTypeMapListener) {
            imListener.onMessage(data);
        }
    }

    /**
     * 处理{@link CoreService}
     * 回调过来的消息
     *
     * @param type 消息类型：0-登录成功；1-登录失败；2-连接成功；3-断开连接
     * @param msg  提示消息
     */
    private void onStatusChange(final int type, final String msg) {
        IMUtils.log("socket:     type：" + type + "，msg：" + msg);
        MsgMgr.getInstance().sendMsg(MsgType.MT_App_IMStatus, new HashMap<String, Object>() {
            {
                put("type", type);
                put("msg", msg);
            }
        });
    }

    private boolean isSocketValid = false;//socket是否在线

    /**
     * @return 判断socket是否在线true表示socket存活并且保持在线状态；false表示socket掉线或者socket对象被杀死
     */
    public boolean isSocketValid() {
        return isSocketValid;
    }

    private void setSocketValidStatus(boolean isSocketValid) {
        this.isSocketValid = isSocketValid;
    }

    /**
     * 重置socket地址和端口
     */
    public void reSetHostPort(String hosts, int port) {
        try {
            if (iCoreService != null) iCoreService.reSetHostPort(hosts, port);
        } catch (Exception e) {
            IMUtils.logThrowable(e);
        }
    }

    /**
     * 获取socket状态
     */
    public int getSocketStatus() {
        try {
            if (iCoreService != null) {
                return iCoreService.getSocketStatus();
            }
        } catch (Exception e) {
            IMUtils.logThrowable(e);
        }
        return SocketState.CONNECTED_SUCCESS.ordinal();
    }
}
